//
// Copyright 1998-2018 by Craig Stuart Sapp, All Rights Reserved.
// Programmer:    Craig Stuart Sapp <craig@ccrma.stanford.edu>
// Creation Date: Sun Apr  5 13:07:18 PDT 1998
// Last Modified: Sat Apr 21 10:52:19 PDT 2018 Removed using namespace std;
// Filename:      midifile/include/Options.h
// Web Address:   http://midifile.sapp.org
// Syntax:        C++11
// vim:           ts=3 noexpandtab
//
// Description:   Interface for command-line options.
//

#ifndef _OPTIONS_H_INCLUDED
#define _OPTIONS_H_INCLUDED

#include <iostream>
#include <map>
#include <string>
#include <vector>

#define OPTION_BOOLEAN_TYPE   'b'
#define OPTION_CHAR_TYPE      'c'
#define OPTION_DOUBLE_TYPE    'd'
#define OPTION_FLOAT_TYPE     'f'
#define OPTION_INT_TYPE       'i'
#define OPTION_STRING_TYPE    's'
#define OPTION_UNKNOWN_TYPE   'x'

namespace smf {

    class Option_register {
    public:
        Option_register(void);

        Option_register(const std::string &aDefinition,
                        char aType,
                        const std::string &aDefaultOption);

        Option_register(const std::string &aDefinition,
                        char aType,
                        const std::string &aDefaultOption,
                        const std::string &aModifiedOption);

        ~Option_register();

        void clearModified(void);

        const std::string &getDefinition(void);

        const std::string &getDefault(void);

        const std::string &getOption(void);

        const std::string &getModified(void);

        const std::string &getDescription(void);

        bool isModified(void);

        char getType(void);

        void reset(void);

        void setDefault(const std::string &aString);

        void setDefinition(const std::string &aString);

        void setDescription(const std::string &aString);

        void setModified(const std::string &aString);

        void setType(char aType);

        std::ostream &print(std::ostream &out);

    protected:
        std::string definition;
        std::string description;
        std::string defaultOption;
        std::string modifiedOption;
        bool modifiedQ;
        char type;

    };


    class Options {
    public:
        Options(void);

        Options(int argc, char **argv);

        ~Options();

        int argc(void) const;

        const std::vector<std::string> &argv(void) const;

        int define(const std::string &aDefinition);

        int define(const std::string &aDefinition,
                   const std::string &description);

        const std::string &getArg(int index);

        const std::string &getArgument(int index);

        int getArgCount(void);

        int getArgumentCount(void);

        const std::vector<std::string> &getArgList(void);

        const std::vector<std::string> &getArgumentList(void);

        bool getBoolean(const std::string &optionName);

        std::string getCommand(void);

        const std::string &getCommandLine(void);

        std::string getDefinition(const std::string &optionName);

        double getDouble(const std::string &optionName);

        char getFlag(void);

        char getChar(const std::string &optionName);

        float getFloat(const std::string &optionName);

        int getInt(const std::string &optionName);

        int getInteger(const std::string &optionName);

        std::string getString(const std::string &optionName);

        char getType(const std::string &optionName);

        int optionsArg(void);

        std::ostream &print(std::ostream &out);

        std::ostream &printOptionList(std::ostream &out);

        std::ostream &printOptionListBooleanState(std::ostream &out);

        void process(int error_check = 1,
                     int suppress = 0);

        void process(int argc, char **argv,
                     int error_check = 1,
                     int suppress = 0);

        void reset(void);

        void xverify(int argc, char **argv,
                     int error_check = 1,
                     int suppress = 0);

        void xverify(int error_check = 1,
                     int suppress = 0);

        void setFlag(char aFlag);

        void setModified(const std::string &optionName,
                         const std::string &optionValue);

        void setOptions(int argc, char **argv);

        void appendOptions(int argc, char **argv);

        void appendOptions(const std::string &strang);

        void appendOptions(const std::vector<std::string> &argv);

        std::ostream &printRegister(std::ostream &out);

        bool isDefined(const std::string &name);

    protected:
        int m_options_error_check;  // verify command
        int m_oargc;
        std::vector<std::string> m_oargv;
        std::string m_commandString;
        char m_optionFlag;
        std::vector<std::string> m_argument;

        std::vector<Option_register *> m_optionRegister;
        std::map<std::string, int> m_optionList;

        int m_processedQ;
        int m_suppressQ;       // prevent --options
        int m_optionsArgument; // --options present

        std::vector<std::string> m_extraArgv;
        std::vector<std::string> m_extraArgv_strings;

    private:
        int getRegIndex(const std::string &optionName);

        int optionQ(const std::string &aString,
                    int &argp);

        int storeOption(int gargp, int &position,
                        int &running);

    };

} // end of namespace smf


#endif  /* _OPTIONS_H_INCLUDED */



